# 开启PAE分页 ## 1.获取CPU的最大带宽 ​ 要开启PAE,必须要获得CPU的最大带宽,这可以通过CPUID.0x80000_0008指令获得: 在Loader.asm最后一行加上一下指令: ```nasm mov eax,0x8000_0008 cpuid hlt ;休眠CPU ``` make调试结果如下: > Next at t=0 > (0) \[0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 > \ c > Next at t=6085757593 > (0) [0x000000000968] 0008:0000000000000968 (unk. ctxt): mov ebx, 0x00100000 ; bb00001000 > \ reg > **rax: 00000000_00003028** rcx: 00000000_00000000 > rdx: 00000000_00000000 rbx: 00000000_00000000 > rsp: 00000000_00000900 rbp: 00000000_00007c63 > rsi: 00000000_000e0000 rdi: 00000000_0000fdbe > r8 : 00000000_00000000 r9 : 00000000_00000000 > r10: 00000000_00000000 r11: 00000000_00000000 > r12: 00000000_00000000 r13: 00000000_00000000 > r14: 00000000_00000000 r15: 00000000_00000000 > rip: 00000000_00000968 > eflags 0x00000006: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af PF cf > \ q > (0).\[6085757593][0x000000000968] 0008:0000000000000968 (unk. ctxt): mov ebx, 0x00100000 ; bb00001000 ​ 可以看到:执行`cpuid`指令后,`rax=0x3028=11_0000_0010_1000`,其中,前8位=40,因此,虚拟机的最大带宽为40。 ## 2.查看CPU是否支持PAT 将上述代码更改为: ```nasm mov eax,0x1 cpuid hlt ``` Bochs调试结果如下: > Next at t=0 > (0) \[0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 > \ c > Next at t=4236232103 > (0)\ [0x000000000968] 0008:0000000000000968 (unk. ctxt): mov ebx, 0x00100000 ; bb00001000 > \ reg > rax: 00000000_000206a7 rcx: 00000000_079ae3bf > **rdx: 00000000_bfebfbff** rbx: 00000000_00010800 > rsp: 00000000_00000900 rbp: 00000000_00007c63 > rsi: 00000000_000e0000 rdi: 00000000_0000fdbe > r8 : 00000000_00000000 r9 : 00000000_00000000 > r10: 00000000_00000000 r11: 00000000_00000000 > r12: 00000000_00000000 r13: 00000000_00000000 > r14: 00000000_00000000 r15: 00000000_00000000 > rip: 00000000_00000968 > eflags 0x00000006: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af PF cf > \ q > (0).\[4236232103][0x000000000968] 0008:0000000000000968 (unk. ctxt): mov ebx, 0x00100000 ; bb00001000 ​ 可以看到,执行CPUID后,`rdx.16bits=1`,可以看到,模拟器支持PAT。 由于在支持PAT的PAE分页下,PCD和PWT的值来自关联的PDPTE寄存器,所以这里设置为0。 ## 3.开启PAE 实现代码如下: ```nasm ;---------------保护模式初始化完成-------------------- ;下面准备PAE分页 ;现在仅映射4G内存 ;将PAE放到低端1M空间之上 Paging: PDPTE_BASE equ 0x100_000 PDE_BASE equ 0x101000 PTE_BASE equ 0x105000 ;四个页目录表占用16KB mov ebx,PDPTE_BASE ;创建页目录指针表 mov eax,0x8080800 ;第一个页目录表 mov [ebx+4],eax mov [ebx+12],eax mov [ebx+20],eax mov [ebx+28],eax mov ecx,512 ;创建页目录表 mov ebx,PDE_BASE mov eax,PTE_BASE add eax,7 push ebp ;现在ebp不为0 mov ebp,0 .create_pde: mov [ebx+ebp],eax add ebp,8 add eax,0x40000 ;每个页目录映射2M空间 loop .create_pde mov ecx,0x40000 ;创建页表 mov ebx,PTE_BASE mov eax,7 mov ebp,0 .create_pte: mov [ebx+ebp],eax add ebp,8 add eax,409 loop .create_pte mov eax,0x0200_0000 mov cr3,eax mov eax,cr4 or eax,1_00000b mov cr4,eax ;EFER.LME=1 mov ecx,0xc0000080 rdmsr ;将EFER读取到EDX:EAX中 or eax,1_00000000b wrmsr mov eax,cr0 or eax,0x80000000 mov cr0,eax hlt ``` ​ 其中,rdmsr和wrmsr指令与中断类似,但是使用ecx储存MSR号(EFER的MSR号为`0xc0000080`),并将结果读取到EDX:EAX中。 ​ Bochs调试结果如下: > Next at t=0 > (0) \[0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 > \ show mode > show mode switch: ON > show mask is: mode > \ b 0x9e6 > \ c > 00000362789: switched from 'real mode' to 'protected mode' > 00001713048: switched from 'protected mode' to 'real mode' > 00001713058: switched from 'real mode' to 'protected mode' > 00001901775: switched from 'protected mode' to 'real mode' > 00006122382: switched from 'real mode' to 'protected mode' > 00007173032: address space switched. CR3: 0x000002000000 > **00007173042: switched from 'protected mode' to 'compatibility mode'** > (0).\[7173042] ??? (physical address not available) > Next at t=7173043 > (0) \[0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 > \ q > (0).\[7173043][0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 ​ 可以看到loader已经进入IA32-e模式,但是结果却导致CPU复位:` jmpf 0xf000:e05b`结果有待改进。 在多次调试过程中发现: ​ 当EPER.LME打开时,CPU并没有进入IA-32e模式,只有在PG为打开后才进入。